// vim: ts=4:sw=4:nu:fdc=2:nospell
/**
  * Ext.ux.HttpProvider extension
  *
  * @author    Ing. Jozef Sakalos
  * @copyright (c) 2008, Ing. Jozef Sakalos
  * @version $Id: Ext.ux.HttpProvider.js 676 2008-02-03 00:57:01Z jozo $
  *
  * @class Ext.ux.HttpProvider
  * @extends Ext.state.Provider
  * @constructor
  */
// {{{
Ext.ux.HttpProvider = function(config) {

    this.addEvents('readsuccess', 'readfailure', 'savesuccess', 'savefailure');

    // call parent 
    Ext.ux.HttpProvider.superclass.constructor.call(this);

    Ext.apply(this, config, {
        // defaults
         delay:750 // buffer changes for 750 ms
        ,dirty:false
        ,started:false
        ,autoStart:true
        ,autoRead:true
        ,user:'user'
        ,id:1
        ,session:'session'
        ,logFailure:false
        ,logSuccess:false
        ,queue:[]
        ,url:'.'
        ,readUrl:undefined
        ,saveUrl:undefined
        ,method:'post'
        ,saveBaseParams:{}
        ,readBaseParams:{}
        ,paramNames:{
             id:'id'
            ,name:'name'
            ,value:'value'
            ,user:'user'
            ,session:'session'
            ,data:'data'
        }
    }); // e/o apply

    if(this.autoRead) {
        this.readState();
    }

    this.dt = new Ext.util.DelayedTask(this.submitState, this);
    if(this.autoStart) {
        this.start();
    }
}; // e/o constructor
// }}}

Ext.extend(Ext.ux.HttpProvider, Ext.state.Provider, {

    // localizable texts
     saveSuccessText:'Save Success'
    ,saveFailureText:'Save Failure'
    ,readSuccessText:'Read Success'
    ,readFailureText:'Read Failure'
    ,dataErrorText:'Data Error'

    // {{{
    ,initState:function(state) {
        if(state instanceof Array) {
            Ext.each(state, function(item) {
                this.state[item.name] = this.decodeValue(item.value);
            }, this);
        }
        else {
            this.state = state ? state : {};
        }
    } // e/o function initState
    // }}}
    // {{{
    ,set:function(name, value) {
        if(!name) {
            return;
        }

        this.queueChange(name, value);

    } // e/o function set
    // }}}
    // {{{
    ,start:function() {
        this.dt.delay(this.delay);
        this.started = true;
    } // e/o function start
    // }}}
    // {{{
    ,stop:function() {
        this.dt.cancel();
        this.started = false;
    } // e/o function stop
    // }}}
    // {{{
    ,queueChange:function(name, value) {
        var changed = undefined === this.state[name] || this.state[name] !== value;
        var o = {};
        if(changed) {
            o[this.paramNames.name] = name;
            o[this.paramNames.value] = this.encodeValue(value);
            this.queue.push(o);
            this.dirty = true;
        }
        return changed;
    } // e/o function bufferChange
    // }}}
    // {{{
    ,submitState:function() {
        if(!this.dirty) {
            this.dt.delay(this.delay);
            return;
        }
        this.dt.cancel();

        var o = {
             url:this.saveUrl || this.url
            ,method:this.method
            ,scope:this
            ,success:this.onSaveSuccess
            ,failure:this.onSaveFailure
            ,queue:this.queue
            ,params:{}
        };

        var params = Ext.apply({}, this.saveBaseParams);
        params[this.paramNames.id] = this.id;
        params[this.paramNames.user] = this.user;
        params[this.paramNames.session] = this.session;
        params[this.paramNames.data] = Ext.encode(this.queue);

        Ext.apply(o.params, params);
        Ext.Ajax.request(o);
    } // e/o function submitState
    // }}}
    // {{{
    ,clear:function(name) {
        this.set(name, undefined);
    } // e/o function clear
    // }}}
    // {{{
    ,onSaveSuccess:function(response, options) {
        if(this.started) {
            this.start();
        }
        var o = {};
        try {o = Ext.decode(response.responseText)}
        catch(e) {
            if(true === this.logFailure) {
                this.log(this.saveFailureText, e, response);
            }
            return;
        }
        if(true !== o.success) {
            if(true === this.logFailure) {
                this.log(this.saveFailureText, o, response);
            }
        }
        else {
            Ext.each(options.queue, function(item) {
                var name = item[this.paramNames.name];
                var value = this.decodeValue(item[this.paramNames.value]);

                if(undefined === value || null === value) {
                    Ext.ux.HttpProvider.superclass.clear.call(this, name);
                }
                else {
                    // parent sets value and fires event
                    Ext.ux.HttpProvider.superclass.set.call(this, name, value);
                }
            }, this);
            this.queue = [];
            this.dirty = false;
            if(true === this.logSuccess) {
                this.log(this.saveSuccessText, o, response);
            }
            this.fireEvent('savesuccess', this);
        }
    } // e/o function onSaveSuccess
    // }}}
    // {{{
    ,onSaveFailure:function(response, options) {
        if(true === this.logFailure) {
            this.log(this.saveFailureText, response);
        }
        if(this.started) {
            this.start();
        }
        this.fireEvent('savefailure', this);
    } // e/o function onSaveFailure
    // }}}
    // {{{
    ,onReadFailure:function(response, options) {
        if(true === this.logFailure) {
            this.log(this.readFailureText, response);
        }
        this.fireEvent('readfailure', this);

    } // e/o function onReadFailure
    // }}}
    // {{{
    ,onReadSuccess:function(response, options) {
        var o = {}, data;
        try {o = Ext.decode(response.responseText)}
        catch(e) {
            if(true === this.logFailure) {
                this.log(this.readFailureText, e, response);
            }
            return;
        }
        if(true !== o.success) {
            if(true === this.logFailure) {
                this.log(this.readFailureText, o, response);
            }
        }
        else {
            try {data = Ext.decode(o[this.paramNames.data])}
            catch(e) {
                if(true === this.logFailure) {
                    this.log(this.dataErrorText, o, response);
                }
                return;
            }
            if(!(data instanceof Array) && true === this.logFailure) {
                this.log(this.dataErrorText, data, response);
                return;
            }
            Ext.each(data, function(item) {
                this.state[item[this.paramNames.name]] = this.decodeValue(item[this.paramNames.value]);
            }, this);
            this.queue = [];
            this.dirty = false;
            if(true === this.logSuccess) {
                this.log(this.readSuccessText, data, response);
            }
            this.fireEvent('readsuccess', this);
        }
    } // e/o function onReadSuccess
    // }}}
    //

    // {{{
    ,readState:function() {
        var o = {
             url:this.readUrl || this.url
            ,method:this.method
            ,scope:this
            ,success:this.onReadSuccess
            ,failure:this.onReadFailure
            ,params:{}
        };

        var params = Ext.apply({}, this.readBaseParams);
        params[this.paramNames.id] = this.id;
        params[this.paramNames.user] = this.user;
        params[this.paramNames.session] = this.session;

        Ext.apply(o.params, params);
        Ext.Ajax.request(o);
    } // e/o function readState
    // }}}
    // {{{
    ,log:function() {
        if(console) {
            console.log.apply(console, arguments);
        }
    } // e/o log
    // }}}

}); // e/o extend